package com.zzyl.nursing.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.entity.SysUser;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.bean.BeanUtils;
import com.zzyl.framework.config.properties.HuaWeiIotConfigProperties;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.ChangeDeviceDTO;
import com.zzyl.nursing.dto.DeviceDTO;
import com.zzyl.nursing.dto.DeviceDetailDTO;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.*;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DeviceVO;
import com.zzyl.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备表Service业务层处理
 *
 * @author mr.luo
 * @date 2025-05-25
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IoTDAClient iotDAClient;
    @Autowired
    private IDeviceDataService iDeviceDataService;

    /**
     * 查询设备表
     *
     * @param id 设备表主键
     * @return 设备表
     */
    @Override
    public Device selectDeviceById(Long id) {
        return getById(id);
    }

    /**
     * 查询设备表列表
     *
     * @param device 设备表
     * @return 设备表
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备表
     *
     * @param device 设备表
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return save(device) ? 1 : 0;
    }

    /**
     * 修改设备表
     *
     * @param device 设备表
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        return updateById(device) ? 1 : 0;
    }

    /**
     * 批量删除设备表
     *
     * @param ids 需要删除的设备表主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除设备表信息
     *
     * @param id 设备表主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id) {
        return removeById(id) ? 1 : 0;
    }


    /**
     * 同步产品列表
     */
    @Override
    public void syncProductList() {
        //获取设备列表
        ListProductsResponse listProductsResponse = iotDAClient.listProducts(new ListProductsRequest());
        //获取设备列表
        List<ProductSummary> products = listProductsResponse.getProducts();
        //检测设备列表
        if (listProductsResponse.getHttpStatusCode() != 200 || products == null) {
            throw new BaseException("获取设备列表失败");
        }
        //使用String类型 上传到redis中
        redisTemplate.opsForValue().set(CacheConstants.DEVICE_FILE_KEY, JSON.toJSONString(products));
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<DeviceVO> allProduct() {
        //从Redis中获取数据
        String s = redisTemplate.opsForValue().get(CacheConstants.DEVICE_FILE_KEY);
        if (StrUtil.isBlank(s)) {
            throw new BaseException("获取设备列表失败");
        }
        //转化为集合VO
        List<ProductSummary> list = JSONUtil.toList(s, ProductSummary.class);
        List<DeviceVO> collect = list.stream().map(d -> {
            return DeviceVO.builder().productKey(d.getProductId()).productName(d.getName()).build();
        }).collect(Collectors.toList());
        return collect;
    }


    /**
     * 注册设备
     *
     * @param deviceDTO
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void register(DeviceDTO deviceDTO) {
        String nickname = deviceDTO.getNickname();
        //判断设备名称是否重复，查询数据库的表
        Long count = lambdaQuery().eq(Device::getDeviceName, deviceDTO.getDeviceName()).count();
        if (count > 0) {
            throw new BaseException("设备名称重复");
        }
        //判断设备标识是否重复(由于前端并没有传一个设备标识，所以要生成一个唯一标识，然后去数据库中查找，看是否重复)
        //生成雪花算法的设备标识
        String nodeId = IdUtil.getSnowflakeNextIdStr();
        Long count1 = lambdaQuery().eq(Device::getNodeId, nodeId).count();
        if (count1 > 0) {
            throw new BaseException("设备标识重复");
        }
        //判断同一位置是否绑定了相同的产品
        Long count2 = lambdaQuery().eq(Device::getLocationType, deviceDTO.getLocationType())
                .eq(Device::getBindingLocation, deviceDTO.getBindingLocation())
                .eq(Device::getProductKey, deviceDTO.getProductKey()).count();
        if (count2 > 0) {
            throw new BaseException("同一位置已绑定相同产品");
        }
        //注册设备 构建设备信息
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        //设置设备标识码
        body.setNodeId(nodeId);
        //设置设备名称
        body.setDeviceName(deviceDTO.getDeviceName());
        // 设置产品ID
        body.setProductId(deviceDTO.getProductKey());
        // 设置设备备注名称
        body.setDescription(nickname);

        // 创建设备
        AuthInfo authInfobody = new AuthInfo();

        String secret = IdUtil.simpleUUID();
        authInfobody.setSecret(secret);
        body.setAuthInfo(authInfobody);
        request.setBody(body);
        // addDeviceResponse 是 创建设备返回结果
        AddDeviceResponse addDeviceResponse = iotDAClient.addDevice(request);
        if (addDeviceResponse.getHttpStatusCode() != 201) {
            throw new BaseException("设备创建失败");
        }

        Device device = new Device();
        BeanUtils.copyProperties(deviceDTO, device);
        //保存设备到表中
        device.setNodeId(nodeId);//前面生成的设备标识码
        device.setIotId(addDeviceResponse.getDeviceId());//设备ID由物联网平台分配获得，生成规则为product_id + _ + node_id拼接而成
        device.setNickname(nickname);//设备备注名称（设备描述）
        device.setDeviceDescription(nickname);//设备备注名称（设备描述）
        device.setSecret(secret);//前面生成的设备密钥

        String productName = this.getProductNameFromCache(deviceDTO.getProductKey());
        device.setProductName(productName);//产品名称
        this.save(device);
    }

    /**
     * 从缓存中根据产品ID获取产品名
     *
     * @param productAppId
     * @return
     */
    private String getProductNameFromCache(String productAppId) {
        //从Redis查询产品列表JSON字符串
        String productListJson = redisTemplate.opsForValue().get(CacheConstants.DEVICE_FILE_KEY);
        if (StringUtils.isBlank(productListJson)) {
            return null;
        }

        //解析JSON为产品列表
        List<ProductSummary> productList = JSONUtil.toList(productListJson, ProductSummary.class);
        ProductSummary product = productList.stream().filter(x -> productAppId.equals(x.getProductId())).findFirst().get();
        return product.getName();
    }

    @Autowired
    private HuaWeiIotConfigProperties huaWeiIotConfigProperties;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private IElderService iElderService;
    @Autowired
    private IFloorService iFloorService;
    @Autowired
    private IRoomService iRoomService;
    @Autowired
    private IBedService iBedService;

    /**
     * 查询设备的详细信息
     *
     * @param deviceDetailDTO
     * @return
     */
    @Override
    public DeviceDetailVo getDeviceDetail(DeviceDetailDTO deviceDetailDTO) {

        DeviceDetailVo deviceDetailVo = new DeviceDetailVo();
        //首先先查表中数据是否存在该设备
        //物联网设备id
        String iotId = deviceDetailDTO.getIotId();
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        if (device == null) {
            throw new BaseException("该设备不存在");
        }
        //然后给VO赋值
        BeanUtils.copyProperties(device, deviceDetailVo);
        //位置类型 0：随身设备 1：固定设备
        if (device.getLocationType() == 0) {
            //注意新增的时候绑定的的位置就是老人的ID或者床的ID 楼层id 楼层的id
            Elder elder = iElderService.getById(device.getBindingLocation());
            //应该是随身绑定的老人的姓名
            deviceDetailVo.setRemark(elder.getName());
            deviceDetailVo.setBindingLocation(String.valueOf(elder.getId()));
            //"物理位置类型 0楼层 1房间 2床位"
        } else if (device.getLocationType() == 1) {
            Integer physicalLocationType = device.getPhysicalLocationType();
            if (physicalLocationType == 0) {
                //所以此时的绑定位置就是楼层的ID
                Floor floor = iFloorService.getById(device.getBindingLocation());
                deviceDetailVo.setRemark(floor.getName());
                deviceDetailVo.setBindingLocation(String.valueOf(floor.getId()));
            } else if (physicalLocationType == 1) {
                //所以此时的绑定位置就是房间的ID
                Room room = iRoomService.getById(device.getBindingLocation());
                deviceDetailVo.setRemark(room.getCode());
                deviceDetailVo.setBindingLocation(String.valueOf(room.getId()));
            } else if (physicalLocationType == 2) {
                //所以此时的绑定位置就是床的ID
                Bed bed = iBedService.getById(device.getBindingLocation());
                deviceDetailVo.setRemark(bed.getBedNumber());
                deviceDetailVo.setBindingLocation(String.valueOf(bed.getId()));
            }
        }

        //给VO补充表中存在拷贝不上的信息
        deviceDetailVo.setIotId(iotId);
        deviceDetailVo.setProductKey(deviceDetailDTO.getProductKey());
        deviceDetailVo.setRegion(huaWeiIotConfigProperties.getRegionId());
        //查询云端数据
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(iotId);
        ShowDeviceResponse response = iotDAClient.showDevice(request);
        //给VO补充数据
        deviceDetailVo.setDeviceStatus(response.getStatus());
        String activeTime = response.getActiveTime();
        LocalDateTime gmtActive = OffsetDateTime.parse(activeTime).atZoneSameInstant(ZoneId.of("Asia/Shanghai")).toLocalDateTime();
        deviceDetailVo.setGmtActive(gmtActive);
        deviceDetailVo.setGmtCreate(device.getCreateTime());
        deviceDetailVo.setCreateBy(device.getCreateBy());
        SysUser sysUser = iSysUserService.selectUserById(Long.valueOf(device.getCreateBy()));
        deviceDetailVo.setCreator(sysUser.getUserName());
        deviceDetailVo.setDeviceSecret(device.getSecret());
        deviceDetailVo.setFirmwareVersion(response.getFwVersion());
        deviceDetailVo.setStatus(response.getStatus());
        return deviceDetailVo;
    }

    /**
     * 1.6 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param productKey
     */
    @Override
    public JSONObject getProductDetail(String productKey) {
        //调用华为云查看产品的SDK Api
        ShowProductRequest request = new ShowProductRequest();
        request.withProductId(productKey);
        ShowProductResponse response = iotDAClient.showProduct(request);
        //判断
        if (response == null || response.getHttpStatusCode() != 200) {
            throw new BaseException("查看产品失败");
        }
        //解析响应结果
        List<ServiceCapability> serviceCapabilities = response.getServiceCapabilities();
        if (CollectionUtils.isEmpty(serviceCapabilities)) {
            throw new BaseException("查看产品失败");
        }
        ServiceCapability serviceCapability = serviceCapabilities.get(0);
        JSONObject entries = JSONUtil.parseObj(serviceCapability);
        return entries;
    }

    /**
     * 1.7 查询指定设备的物模型运行状态
     *
     * @param deviceDTO
     */
    @Override
    public Map<String, Object> getDeviceStatus(DeviceDTO deviceDTO) {
        String deviceName = deviceDTO.getDeviceName();
        String productKey = deviceDTO.getProductKey();
        //首先判断设备是否存在
        Device device = lambdaQuery().eq(Device::getDeviceName, deviceName)
                .eq(Device::getProductKey, productKey)
                .select(Device::getIotId)
                .one();
        if (device == null) {
            throw new BaseException("设备不存在");
        }
        //调用华为云的接口，查询设备影子数据
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.withDeviceId(device.getIotId());
        ShowDeviceShadowResponse response = iotDAClient.showDeviceShadow(request);
        //解析数据
        List<DeviceShadowData> shadow = response.getShadow();
        if (CollectionUtils.isEmpty(shadow)) {
            throw new BaseException("设备不存在");
        }
        DeviceShadowData deviceShadowData = shadow.get(0);
        DeviceShadowProperties reported = deviceShadowData.getReported();
        String eventTimeStr = reported.getEventTime();
        //格式化时间
        LocalDateTime eventTime = OffsetDateTime.parse(eventTimeStr, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                .atZoneSameInstant(ZoneId.of("Asia/Shanghai")).toLocalDateTime();
        //构建返回数据
        JSONObject entries = JSONUtil.parseObj(reported.getProperties());

        List<Map<String, Object>> propertiesList = new ArrayList<>();
        entries.forEach((k, v) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("identifier", k);
            map.put("value", v);
            map.put("time", eventTime);
            propertiesList.add(map);
        });
        Map<String, Object> propertyStatusInfo = new HashMap<>();
        propertyStatusInfo.put("propertyStatusInfo", propertiesList);

        Map<String, Object> result = new HashMap<>();
        result.put("list", propertyStatusInfo);
        return result;
    }


    /**
     * 1.8 修改设备备注名称
     *
     * @param changeDeviceDTO
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeDevice(ChangeDeviceDTO changeDeviceDTO) {
        //通过id查询设备的iot_id
        Device device = lambdaQuery().eq(Device::getId, changeDeviceDTO.getId()).one();
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.withDeviceId(device.getIotId());
        UpdateDevice body = new UpdateDevice();
        AuthInfoWithoutSecret authInfobody = new AuthInfoWithoutSecret();
        authInfobody.withSecureAccess(true);
        body.withAuthInfo(authInfobody);
        body.withExtensionInfo("{\"aaa\":\"xxx\",\"bbb\":0}");
        body.withDescription(changeDeviceDTO.getDeviceDescription());
        body.withDeviceName(changeDeviceDTO.getDeviceName());
        request.withBody(body);
        UpdateDeviceResponse response = iotDAClient.updateDevice(request);
        if (response == null || response.getHttpStatusCode() != 200) {
            throw new BaseException("修改失败");
        }
        //修改数据库中device表中的数据
//        if (StringUtils.isNoneBlank(changeDeviceDTO.getBindingLocation())) {
//            device.setBindingLocation(changeDeviceDTO.getBindingLocation());
//        }
//        if (StringUtils.isNoneBlank(changeDeviceDTO.getDeviceDescription())) {
//            device.setDeviceDescription(changeDeviceDTO.getDeviceDescription());
//        }
//        if (StringUtils.isNoneBlank(changeDeviceDTO.getDeviceName())) {
//            device.setDeviceName(changeDeviceDTO.getDeviceName());
//        }
//        if (changeDeviceDTO.getLocationType() != null) {
//            device.setLocationType(changeDeviceDTO.getLocationType());
//        }
//        if (changeDeviceDTO.getPhysicalLocationType() != null) {
//            device.setPhysicalLocationType(changeDeviceDTO.getPhysicalLocationType());
//        }
//        if (StringUtils.isNoneBlank(changeDeviceDTO.getNickname())) {
//            device.setNickname(changeDeviceDTO.getNickname());
//        }
//        if (StringUtils.isNoneBlank(changeDeviceDTO.getProductKey())) {
//            device.setProductKey(changeDeviceDTO.getProductKey());
//        }
//        if (StringUtils.isNoneBlank(changeDeviceDTO.getRemark())) {
//            device.setRemark(changeDeviceDTO.getRemark());
//        }
        BeanUtils.copyProperties(changeDeviceDTO, device);
        boolean b = this.updateById(device);
        if (!b) {
            throw new BaseException("修改失败");
        }
    }

    /**
     * 删除设备
     *
     * @param deviceDetailDTO
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteDevice(DeviceDetailDTO deviceDetailDTO) {
        String iotId = deviceDetailDTO.getIotId();
        String productKey = deviceDetailDTO.getProductKey();
        //删除设备
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.withDeviceId(deviceDetailDTO.getIotId());
        DeleteDeviceResponse response = iotDAClient.deleteDevice(request);
        if (response == null || response.getHttpStatusCode() != 204) {
            throw new BaseException("删除失败");
        }

        //删除device表中的设备数据
        boolean remove = remove(Wrappers.<Device>lambdaQuery().eq(Device::getIotId, iotId)
                .eq(Device::getProductKey, productKey));
        if (!remove) {
            throw new BaseException("删除device表数据失败");
        }
        //删除device_data表中的相关数据
        iDeviceDataService.remove(Wrappers.<DeviceData>lambdaQuery().eq(DeviceData::getIotId, iotId)
                .eq(DeviceData::getProductKey, productKey));

    }
}
